#include "daemon_process.h"
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
#include "log/log.h"

#define EXECUTABLE "/usr/bin/gateway"

typedef struct
{
    pid_t pid;
    char *cmd;
    char **argv;
} DaemonProcessObj;

DaemonProcess daemon_process_create(char *part)
{
    // 如果part既不是ota也不是app，则返回NULL
    if (strcmp(part, "app") && strcmp(part, "ota"))
    {
        log_error("Invalid part %s", part);
        return NULL;
    }

    // 申请子进程对象内存
    DaemonProcessObj *obj = malloc(sizeof(DaemonProcessObj));
    if (!obj)
    {
        goto OBJ_ALLOC_ERROR;
    }

    memset(obj, 0, sizeof(DaemonProcessObj));

    // 初始化子进程命令行参数
    obj->cmd = EXECUTABLE;
    obj->argv = malloc(sizeof(char *) * 3);
    if (!obj->argv)
    {
        goto ARGV_ALLOC_ERROR;
    }
    obj->argv[0] = obj->cmd;
    obj->argv[1] = strdup(part);
    if (!obj->argv[1])
    {
        goto ARGV_DUP_FAIL;
    }
    obj->argv[2] = NULL;
    return obj;

ARGV_DUP_FAIL:
    free(obj->argv);
ARGV_ALLOC_ERROR:
    free(obj);
OBJ_ALLOC_ERROR:
    return NULL;
}

void daemon_process_checkAndRun(DaemonProcess handle)
{
    DaemonProcessObj *obj = handle;
    if (obj->pid != 0)
    {
        // 不是第一次启动，查看进程状态
        pid_t result = waitpid(obj->pid, NULL, WNOHANG);
        if (result == -1)
        {
            log_fatal("Waitpid func returns -1!!!!");
            exit(EXIT_FAILURE);
        }
        if (result == 0)
        {
            // 子进程还在运行
            return;
        }
    }
    // 走到这里，子进程要么是第一次执行，要么已经挂了
    obj->pid = fork();
    if (obj->pid < 0)
    {
        log_fatal("Fork failed!!!!");
        exit(EXIT_FAILURE);
    }
    if (obj->pid > 0)
    {
        // 父进程
        log_info("Fork success, child part is %s, child pid is %d", obj->argv[1], obj->pid);
        return;
    }
    // 子进程，启动程序
    if (execve(obj->cmd, obj->argv, __environ) < 0)
    {
        log_error("Execve failed");
        exit(EXIT_FAILURE);
    }
}

void daemon_process_stop(DaemonProcess handle)
{
    DaemonProcessObj *obj = handle;
    if (kill(obj->pid, SIGTERM) < 0)
    {
        log_warn("Signal send for child %d failed", obj->pid);
        return;
    }
    waitpid(obj->pid, NULL, 0);
}

void daemon_process_destroy(DaemonProcess handle)
{
    if (!handle)
    {
        return;
    }
    DaemonProcessObj *obj = handle;
    free(obj->argv[1]);
    free(obj->argv);
    free(obj);
}
